/************************************************************************
* image_tga.c
* voxelands - 3d voxel world sandbox game
* Copyright (C) Lisa 'darkrose' Milne 2016 <lisa@ltmnet.com>
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful, but
* WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
* See the GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program.  If not, see <http://www.gnu.org/licenses/>
************************************************************************/

#include "common.h"
#include "graphics.h"
#include "file.h"
#include "path.h"

#include <string.h>

static unsigned char tga_uncompressed[12] = {0,0,2,0,0,0,0,0,0,0,0,0};
static unsigned char tga_compressed[12] = {0,0,10,0,0,0,0,0,0,0,0,0};

/* is it a tga image? */
int image_is_tga(file_t *f)
{
	if (!memcmp(f->data,tga_compressed,12))
		return 1;
	if (!memcmp(f->data,tga_uncompressed,12))
		return 1;
	return 0;
}

/* load a tga image to pixel data */
int image_load_tga(file_t *f, image_t *p)
{
	int compressed = 0;
	int bpp;
	int size;
	register int i;
	int k;
	unsigned char header[18];

	file_read(f,header,18);

	if (!memcmp(header,tga_compressed,12)) {
		compressed = 1;
	}else if (memcmp(header,tga_uncompressed,12)) {
		return 1;
	}

	p->w = (header[13]*256)+header[12];
	p->h = (header[15]*256)+header[14];
	bpp = header[16]/8;
	if (bpp < 3 || bpp > 4)
		return 1;

	size = p->w*p->h*bpp;

	p->pixels = malloc(p->w*p->h*4);

	if (compressed) {
		unsigned int pixelcount	= p->w*p->h;
		unsigned int currentpixel = 0;
		unsigned char chunkheader;
		unsigned char colour[4];
		k = 0;
		do {
			file_read(f,&chunkheader,1);

			if(chunkheader < 128) {
				chunkheader++;

				for (i=0; i<chunkheader; i++) {
					file_read(f,colour,bpp);

					/* BGR -> RGB */
					p->pixels[k] = colour[2];
					p->pixels[k+1] = colour[1];
					p->pixels[k+2] = colour[0];

					/* ensure there's an alpha value */
					if (bpp == 4) {
						p->pixels[k + 3] = colour[3];
					}else{
						p->pixels[k + 3] = 255;
					}

					k += 4;
					currentpixel++;

					if (currentpixel > pixelcount) {
						free(p->pixels);
						return 1;
					}
				}
			}else{
				chunkheader -= 127;

				file_read(f,colour,bpp);

				for (i=0; i<chunkheader; i++) {
					/* BGR -> RGB */
					p->pixels[k] = colour[2];
					p->pixels[k+1] = colour[1];
					p->pixels[k+2] = colour[0];

					/* ensure there's an alpha value */
					if (bpp == 4) {
						p->pixels[k + 3] = colour[3];
					}else{
						p->pixels[k + 3] = 255;
					}

					k += 4;
					currentpixel++;

					if (currentpixel > pixelcount) {
						free(p->pixels);
						return 1;
					}
				}
			}
		} while (currentpixel < pixelcount);
	}else{
		file_read(f,p->pixels,size);

		if (bpp == 3) {
			/* BGR -> RGBA */
			unsigned char* data = malloc(p->w*p->h*4);
			for (i=0,k=0; i<size; i+=3,k+=4) {
				data[k] = p->pixels[i+2];
				data[k+1] = p->pixels[i+1];
				data[k+2] = p->pixels[i];
				data[k+3] = 255;
			}
			free(p->pixels);
			p->pixels = data;
		}else{
			/* BGRA -> RGBA */
			for (i=0; i<size; i+=bpp) {
				p->pixels[i] ^= p->pixels[i+2];
				p->pixels[i+2] ^= p->pixels[i];
				p->pixels[i] ^= p->pixels[i+2];
			}
		}
	}

	return 0;
}

/* write pixel data to a tga image */
int image_save_tga(image_t *p, char* file)
{
	char buff[2048];
	unsigned char header[18] = {0,0,2,0,0,0,0,0,0,0,0,0,   0,0,0,0,32,0};
	FILE *f;
	int i;
	int sz = p->w*p->h*4;

	header[13] = (p->w&0xFF00)>>8;
	header[12] = p->w&0x00FF;
	header[15] = (p->h&0xFF00)>>8;
	header[14] = p->h&0x00FF;

	if (!path_get(NULL,file,0,buff,2048))
		return 1;
	f = fopen(buff,"wb");
	if (!f)
		return 1;

	fwrite(header,18,1,f);

	/* tga expects BGRA so change it from RGBA */
	for (i=0; i<sz; i+=4) {
		fwrite(&p->pixels[i+2],1,1,f);
		fwrite(&p->pixels[i+1],1,1,f);
		fwrite(&p->pixels[i],1,1,f);
		fwrite(&p->pixels[i+3],1,1,f);
	}

	fclose(f);

	return 0;
}
